﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Skugo.Core
{
    /// <summary>
    /// Any extensions we'd like to add to containers go here.
    /// </summary>
    public static class ContainerEx
    {
        /// <summary>
        /// Erases a particular element by swaping it with the end, and erasing the end.
        /// Runs in O(1), but does not preserve order.
        /// </summary>
        /// <typeparam name="T">The type of element in the list</typeparam>
        /// <param name="list">The list that we'd like to swap erase from</param>
        /// <param name="index">The index that we'd like to erase from the list</param>
        /// <returns>The value that was swapped in its place.</returns>
        public static T SwapErase<T>(this IList<T> list, Int32 index)
        {
            var valueAtEnd = list[list.Count - 1];
            list[index] = valueAtEnd;
            list.RemoveAt(list.Count - 1);
            return valueAtEnd;
        }

        /// <summary>
        /// Remove a linked node from its owning linked list, only if it's currently in a list.
        /// </summary>
        /// <typeparam name="T">The type that the node contains.</typeparam>
        /// <param name="node">The node itself that we're unlinking.</param>
        public static void SafeUnlink<T>(this LinkedListNode<T> node)
        {
            // Check if the node is indeed linked...
            if (node.IsLinked())
            {
                // If so, unlink the node
                node.Unlink();
            }
        }

        /// <summary>
        /// Remove a linked node from its owning linked list.
        /// </summary>
        /// <typeparam name="T">The type that the node contains.</typeparam>
        /// <param name="node">The node itself that we're unlinking.</param>
        public static void Unlink<T>(this LinkedListNode<T> node)
        {
            node.List.Remove(node);
        }

        /// <summary>
        /// Returns if the node is linked to anything currently (does it belong to anything?).
        /// </summary>
        /// <typeparam name="T">The type of the node.</typeparam>
        /// <param name="node">The node that we're checking on (this or self).</param>
        /// <returns>Returns true if it is linked, false otherwise.</returns>
        public static bool IsLinked<T>(this LinkedListNode<T> node)
        {
            return node.List != null;
        }

        /// <summary>
        /// Adds a node to a linked list only if the node is unlinked.
        /// </summary>
        /// <typeparam name="T">The type that we're holding in the container.</typeparam>
        /// <param name="list">The list we wish to add the node to.</param>
        /// <param name="node">The node that we're adding to the list.</param>
        /// <returns>Returns true if successful, false otherwise.</returns>
        public static bool AddIfUnlinked<T>(this LinkedList<T> list, LinkedListNode<T> node)
        {
            // If the node is not linked...
            if (node.IsLinked() == false)
            {
                // Add it to the end of the list
                list.AddLast(node);

                // Return true since we added it to the list
                return true;
            }

            // Return false if we did not add it
            return false;
        }

        /// <summary>
        /// Remove a node from a list if it's already linked to that list.
        /// </summary>
        /// <typeparam name="T">The type that we're holding in the container.</typeparam>
        /// <param name="list">The list that we're removing the node from.</param>
        /// <param name="node">The node that we're removing.</param>
        /// <returns>Returns true if successful, false otherwise.</returns>
        public static bool RemoveIfLinked<T>(this LinkedList<T> list, LinkedListNode<T> node)
        {
            // If the node is linked...
            if (node.IsLinked() == true)
            {
                // Unlink the node from the list
                node.Unlink();

                // Return true since we removed it from the list
                return true;
            }

            // Return false if we did not remove it
            return false;
        }

        public static void Push<T>(this List<T> list, T value)
        {
            list.Add(value);
        }

        public static void Pop<T>(this List<T> list)
        {
            list.RemoveAt(list.Count - 1);
        }

        public static T Peek<T>(this List<T> list, Int32 index)
        {
            // If the index is negative, then we're indexing form the top
            if (index < 0)
            {
                return list[list.Count - index];
            }
            else
            {
                return list[index];
            }
        }

        public static T Peek<T>(this List<T> list)
        {
            return list[list.Count - 1];
        }
    }
}
